home *** CD-ROM | disk | FTP | other *** search
/ Euroscene 2 / Euroscene 2.iso / USEFUL / DeliTracker130 / Developer / Developer.run / Programming.doc < prev   
Encoding:
Text File  |  1992-09-26  |  16.2 KB  |  534 lines

  1. ***************************************************************************
  2. *                     How to write an external Player                     *
  3. ***************************************************************************
  4.  
  5.                 © 1992 by Delirium
  6.                   Date 12.09.1992
  7.  
  8.  
  9.  
  10. DeliTracker supports so called external players. These are players that
  11. are in a special format so that they can be loaded from DeliTracker. If
  12. such a player is loaded, DeliTracker recognises & plays the moduletype that
  13. the player supports. These external players make DeliTracker flexible. New
  14. players can be added by the user and old players can be updated easily. The
  15. user can select only the needed players. The current version DeliTracker
  16. can handle up to 64 external players simultaneously. This should be enough
  17. for the near future :)
  18.  
  19. When DeliTracker is started it will load all the players in the 'DeliPlayers'
  20. directory (or the specified playerpath e.g. tooltypes or in the configfile).
  21. In addition you can add players while DeliTracker is running.
  22.  
  23. External Players are executables which means they are relocated. At the start
  24. of an external player you can find the characteristic playerstructure. This
  25. structure is generated with four macros. These macros can be found in
  26. 'misc/deliplayer.i'.
  27.  
  28. It is not difficult to adapt a player if you have the replayroutine. You only
  29. need to write some interfacecode. DeliTracker has some helpful builtin
  30. routines that will make this job a lot easier. 
  31.  
  32.  
  33. 1. Basics
  34.  
  35. To adapt a new soundsystem you need the replayroutine of that soundsystem, and
  36. at least 5 modules for testing the adaption.
  37.  
  38.  
  39. 2. Schematics of a external player 
  40.  
  41. {
  42.     Playerheader
  43.  
  44.     TagArray
  45.  
  46.     Interfacecode
  47.  
  48.     Replaycode+Data
  49. }
  50.  
  51.  
  52. 3. Functions that the external players (must) have
  53.  
  54. The PLAYERHEADER macro generates the header that identifies the file as a
  55. valid external player for DeliTracker. This macro must exist and the player
  56. must begin with the macro. The only parameter you must supply is a pointer
  57. to a Tag Array that contains all functions that the external player supports.
  58. In all calls to player functions (except the interrupt routine) a5 will
  59. contain the address to the global player datastructure (Base). For more about
  60. this structure read 'misc/deliplayer.i'. In your routines (except in
  61. DTP_Interrupt) you can trash all registers.
  62.  
  63.  
  64. PLAYERHEADER <tagarray>
  65.  
  66.     tagarray    Pointer to a tag array, terminated with TAG_DONE.
  67.             Tags with ti_Data NULL are ignored.
  68.             Here is a summary of all system tags you may use:
  69.               TAG_DONE
  70.               TAG_IGNORE
  71.               TAG_MORE
  72.               TAG_SKIP
  73.  
  74. DTP_CustomPlayer    this tag identifies a player as customplayer.
  75.             ti_Data may not be NULL !
  76.  
  77. DTP_RequestDTVersion    only if the DeliTracker version is greater than or
  78.             equal to the requested version (ti_Data) will
  79.             DeliTracker accept the player. If your player
  80.             uses functions that were introduced in later revisions
  81.             of DeliTracker you must set this tag according to the
  82.             version that introduced this function.
  83.  
  84. DTP_RequestV37        if this tag is set, only the Kick 2.0 version of
  85.             DeliTracker will accept the player.
  86.             (dtg_GadToolsBase is valid)
  87.  
  88. DTP_PlayerVersion    Tag that contains the revision number of the player.
  89.             If there are two players with same name the player
  90.             with the higher version is used.
  91.  
  92. DTP_PlayerName        ti_Data contains a pointer to the playername. This
  93.             string may be as long as you wish, but only the first
  94.             24 chars are actually used. This tag must exist !
  95.  
  96. DTP_Creator        pointer to the author/adaptor name. This string is
  97.             visible    in the prefs window if the player is selected.
  98.             The string may contain $A as line separator.
  99.  
  100. DTP_Check1        pointer to a module identification routine. This
  101.             routine    is called after the first 1024 bytes of the
  102.             module is loaded. If the module is shorter, the rest
  103.             will contain zero. If the routine recognizes the
  104.             moduleformat it must return d0=0 else d0<>0.
  105.  
  106. DTP_Check2        pointer to a module identification routine. This
  107.             routine    is called after the complete module is loaded
  108.             (and decrunched). If the routine recognizes the module
  109.             it must    return d0=0 else d0<>0.
  110.  
  111. DTP_Extload        pointer to a optional loadroutine for modules. If an
  112.             error occurs d0<>0 else d0=0. Please remember to free
  113.             all allocated resources (memory, locks,...), because
  114.             no further player function is called.
  115.  
  116. DTP_Interrupt        pointer to a interruptroutine. This routine is called
  117.             every 1/50 sec. via a timerinterrupt. Note: your
  118.             interruptroutine is not executed in the    timerinterrupt
  119.             itself. This is the standard method for gaining the
  120.             correct playspeed regardless of the videomode. If the
  121.             DTP_Faster/DTP_Slower pointers are not supplied,
  122.             DeliTracker emulates this by changing the interrupt
  123.             frequency. If this tag doesn't exist, you must
  124.             supply DTP_StartInt/DTP_StopInt.
  125.  
  126. DTP_Stop        pointer to optional stop routine. If this tag is not
  127.             exist, DeliTracker uses the following standard method:
  128.                 stop interrupt (DTP_StopInt)
  129.                 cleanup sound (DTP_EndSnd)
  130.                 reinitialize the song (DTP_InitSnd)
  131.             This routine will stop playing the song, reset the
  132.             'patterncounter' to the begin and change the playspeed
  133.             to default. This means that the interrupt is started
  134.             again and the song should begin to play from the
  135.             beginning.
  136.  
  137. DTP_Config        pointer to an optional initialising routine. This
  138.             routine    is only called once after the player is
  139.             loaded. Purpose:
  140.             The player could load a playerspecific configfile.
  141.  
  142. DTP_Userconfig        pointer to a optional initialising routine. This
  143.             routine is called if the user selects the 'Config'
  144.             button in the prefswindow. Purpose: The player could
  145.             open a playerspecific configwindow for setting
  146.             special options (e.g instrumentpath for a sonix
  147.             player) and saving them into a configfile.
  148.  
  149. DTP_SubSongRange    This tag should be supplied if the player supports
  150.             multimodules. ti_Data points to a function that
  151.             returns in d0 the minimum and in d1 the maximum
  152.             subsong number.
  153.  
  154. DTP_InitPlayer        pointer to an initialising routine, that is called if
  155.             a module is loaded successfully. Must return d0=0 if
  156.             all is ok else d0<>0. The audioallocation must be done
  157.             here. (DeliTracker has a function that does the
  158.             allocation.) If the player supports subsongs it has
  159.             to set dtg_SndNum(a5) to the first subsongnumber.
  160.             If a routine for DTP_SubSongRange exists, DeliTracker
  161.             performs this for you and you may omit the
  162.             initialization for dtg_SndNum(a5).
  163.  
  164. DTP_EndPlayer        pointer to a cleanuproutine, that is called if the
  165.             module is removed from memory. Audiochannels have to
  166.             be freed here. (Use the DeliTracker internal
  167.             supportroutine)
  168.  
  169. DTP_InitSound        pointer to an optional initialising routine. This
  170.             routine    has the task to (re)initialize the module. If
  171.             the interrupt is started the song should begin to play
  172.             at the beginning.
  173.  
  174. DTP_EndSound        pointer to an optional cleanuproutine. For example it
  175.             can be used to reset the volumeregister or the
  176.             audio-dma.
  177.  
  178. DTP_StartInt        pointer to an initialising routine, that must exist if 
  179.             DTP_Interrupt doesn't exist. It has the task to start
  180.             the sound.
  181.  
  182. DTP_StopInt        pointer to a cleanuproutine, that must exist if
  183.             DTP_Interrupt doesn't exist. It has the task to stop
  184.             the sound.
  185.  
  186. DTP_Volume        pointer to function that sets the volume. This
  187.             function is called every time the volume is changed
  188.             (via arexx or slider) and once at the initialising
  189.             phase of the module (before DTP_InitSnd is called).
  190.             The mastervolume can be found in dtg_SndVol(a5). The
  191.             mastervolume is the highest volume allowed. The
  192.             effective volume can be calculated using the
  193.             following formula:
  194.             VOL_eff=((MASTERVOLUME*modulevolume)>>6).
  195.             See also the example sources.
  196.  
  197. DTP_Balance        pointer to a function that sets the balance. This
  198.             function is called every time the balance is changed
  199.             (via arexx or slider) and once at the initialising
  200.             phase of the module (before tf_InitSnd is called).
  201.             The balance for the left channel can be found in
  202.             dtg_SndLBal(a5), for the right channel in
  203.             dtg_SndRBal(a5). Note: All players that support
  204.             balance are capable of volume too! Then you must use
  205.             the same routine for both operations. The mastervolume
  206.             for the left channels can be calculated with this
  207.             formula:
  208.             LeftMaster =((dtg_Volume(a5)*dtg_SndLBal(a5))>>6).
  209.             For the right channels the formula is similar.
  210.  
  211. DTP_Faster        pointer to a function that increases the playspeed.
  212.  
  213. DTP_Slower        pointer to a function that decreases the playspeed.
  214.  
  215. DTP_NextPatt        pointer to a function that increases the
  216.             patternpointer.
  217.  
  218. DTP_PrevPatt        pointer to a function that decreases the
  219.             patternpointer.
  220.  
  221. DTP_NextSong        pointer to a function that increases the
  222.             subsongcounter (only if the subsong exists).
  223.  
  224. DTP_PrevSong        pointer to a function that decreases the
  225.             subsongcounter (only if the subsong exists).
  226.  
  227.  
  228. 4. DeliTracker support functions that can be called from the external player.
  229.  
  230. Every function is called like this:
  231.  
  232.     move.l    dtg_XXX(a5),a0        ; a5 must contain the base
  233.     jsr    (a0)
  234.  
  235. All functions (exept dtg_SongEnd) use d0/d1/a0/a1 as Scratchregister.
  236. A5 must contain the base (exept dtg_SongEnd).
  237.  
  238.  
  239. dtg_GetListData
  240.  
  241.     SYNOPSIS
  242.         memory size = dtg_GetListData(number)
  243.             a0     d0                     d0.l
  244.  
  245.     FUNCTION
  246.         Returns the address and the length of a file that was loaded
  247.         with dtg_LoadFile(). 
  248.  
  249.     INPUTS
  250.         number - number of the file beginning with 0 for the file that
  251.              was selected by the user. 
  252.  
  253.     RESULT
  254.         memory - startaddress of the files in memory, if error NULL.
  255.         size - length of the loaded file in bytes or 0 in case of
  256.                an error
  257.  
  258.  
  259. dtg_LoadFile
  260.  
  261.     SYNOPSIS
  262.         success = dtg_LoadFile(name)
  263.  
  264.     FUNCTION
  265.         Loads and decrunches the specified file to chipmemory.
  266.         Note: this function automatically adds '.pp' to the filename.
  267.  
  268.     INPUTS
  269.         name - store the filename in the internal buffer
  270.                (dtg_PathArray contains a pointer to this buffer)
  271.  
  272.     RESULT
  273.         success - success d0.l=0, else d0.l<>0.
  274.  
  275.  
  276. dtg_CopyDir
  277.  
  278.     SYNOPSIS
  279.         dtg_CopyDir()
  280.  
  281.     FUNCTION
  282.         Copies the directory of the selected file at the end
  283.         of the string, that dtg_PathArray points to.
  284.  
  285.  
  286. dtg_CopyFile
  287.  
  288.     SYNOPSIS
  289.          dtg_CopyFile()
  290.  
  291.     FUNCTION
  292.         Copies the filename of the selected file at the end
  293.         of the string, that dtg_PathArray points to.
  294.  
  295.  
  296. dtg_CopyString
  297.  
  298.     SYNOPSIS
  299.         dtg_CopyString(string)
  300.                                a0
  301.  
  302.     FUNCTION
  303.         a0 contains the address of a string, which is copied at the
  304.         end of the string that dtg_PathArray points to.
  305.  
  306.     INPUTS
  307.         string - a0 contains the pointer to the string
  308.  
  309.  
  310. dtg_AudioAlloc
  311.  
  312.     SYNOPSIS
  313.         success = dtg_AudioAlloc()
  314.  
  315.     FUNCTION
  316.         Allocates the audiochannels
  317.  
  318.     RESULT
  319.         success - if we got them: d0.l=0, else d0.l<>0.
  320.  
  321.  
  322. dtg_AudioFree
  323.  
  324.     SYNOPSIS
  325.         dtg_AudioFree()
  326.  
  327.     FUNCTION
  328.         Frees the audiochannels that were allocated with
  329.         dtg_AudioAlloc.
  330.  
  331.  
  332. dtg_StartInt
  333.  
  334.     SYNOPSIS
  335.         dtg_StartInt()
  336.  
  337.     FUNCTION
  338.         Starts the soundinterrupt. If DTP_Interrupt exists,
  339.         DeliTracker starts the internal timerinterrupt, else
  340.         DTP_StartInt is called.
  341.  
  342.  
  343. dtg_StopInt
  344.  
  345.     SYNOPSIS
  346.         dtg_StopInt()
  347.  
  348.     FUNCTION
  349.         Stops the soundinterrupt. If DTP_Interrupt exists,
  350.         DeliTracker stops the internal timerinterrupt, else
  351.         DTP_StopInt is called.
  352.  
  353.  
  354. dtg_SongEnd
  355.  
  356.     SYNOPSIS
  357.         dtg_SongEnd()
  358.  
  359.     FUNCTION
  360.         Signals DeliTracker, that the module was played once.
  361.         This function doesn't change any registers and is save
  362.         to call from interrupts.
  363.  
  364.  
  365. dtg_CutSuffix
  366.  
  367.     SYNOPSIS
  368.         dtg_CutSuffix()
  369.  
  370.     FUNCTION
  371.         removes the suffix '.pp' at the end of the string, that
  372.         dtg_PathArray points to.
  373.  
  374.  
  375.  
  376. 5. Module-Recognition
  377.  
  378. In order to recognize the different moduleformats every player contains a
  379. specific routine, that tells DeliTracker if the player can play this module or
  380. not. This routine has the task to check certain positions in the module that
  381. are identical in every module (like 'M.K.' at offset $438 in NoiseTracker
  382. modules) or significant assembler instructions (if the module contains the
  383. player). Testing against one or two branches or jumps is NOT enough, cause
  384. many modules with player have branchtables at the beginning of the module. If
  385. the player recognizes the wrong module, a system crash will be the result! So
  386. be careful with the Ckeckroutine. As you can see the playerstructure has two
  387. checkfunctions but the player must use exactly one check routine. This leads
  388. to two basic player types:
  389.  
  390.   1.Type one Player
  391.     Here the Check1 function is implemented.
  392.  
  393.     Advantage: You can implement players that can load the module itself.
  394.     Disadvantage: No Packsupport, more complex.
  395.  
  396.     This type should only be used if you REALLY need to load the module by
  397.     yourself!
  398.     (e.g. FTM, IFF-8SVX player that loads the sample while playing, ...) 
  399.     
  400.  
  401.   2. Type two Player - the easier way 
  402.      Here the Check2 function is implemented.
  403.  
  404.     Advantage: The module may be packed and DeliTracker handles the
  405.            loading and allocation of the module for you.
  406.     Disadvantage: The module is completely loaded into CHIP-Memory.
  407.  
  408. Regardless of the playertype the checkfunction must return d0.l=0 if the
  409. player can handle this module or d0.l<>0 if not.
  410.  
  411.  
  412. 6. Player-Interrupt
  413.  
  414.    Players can be divided in two categories:
  415.  
  416.   1. Player that uses the internal timer interrupt from DeliTracker
  417.  
  418.      Advantage: The player is independent from the selected videomode
  419.         The player has automatically the faster/slower function.
  420.         No expense for interrupthandling (interrupt structure
  421.         and the insert/remove code).
  422.         Compatible with the serial.device.
  423.      Disadvantage: The interrupt is not synchronous to the VBlank (This leads
  424.                to problems only to certain cases). 
  425.         
  426.  
  427.   2. Player that generates their own interrupt.
  428.  
  429.      Advantage: You can use other interrupt sources (like AudioIRQ)
  430.         
  431.      Disadvantage: You have to handle the interrupts by yourself, and if
  432.            you use VBlank the player is not independent to the
  433.            videomode.
  434.  
  435.  
  436.     If you use your own timerinterrupt you should allocate CIAB because CIAA
  437.     is used from the system under 2.x. It is wise not to run the soundcode
  438.     directly in the timerinterrupt. Instead you should Cause() a SoftInt in
  439.     the timer interrupt and execute the routine in the SoftInt. This is to
  440.     assure maximum compatibility for modem users because the SoftInt has a
  441.     lower priority thant the RBF interrupt. Beware of writing directly to the
  442.     680x0 intvectors! You should use AddIntServer() or SetIntVector() from
  443.     the OS.
  444.  
  445.  
  446. 7. Custom Modules
  447.  
  448.    These are not modules in the conventional meaning. They are more like
  449.    external players, the difference is that custom modules contain the 
  450.    player AND the module. With the custom module interface you can adapt
  451.    almost every module. If you have more modules with the same replay 
  452.    routine we suggest to write an own player for this moduleformat. 
  453.  
  454.  
  455. Schematic of a custom module (custom player)
  456.  
  457. {
  458.     Playerheader
  459.  
  460.     TagArray
  461.  
  462.     Interfacecode
  463.  
  464.     Replaycode+Data
  465.     
  466.     MODULE
  467. }
  468.  
  469. The Tag DTP_CustomPlayer identifies a player as a custom module.
  470. The following Tags are ignored for custommodules:
  471.  
  472.     - DTP_PlayerVersion
  473.      - DTP_PlayerName
  474.     - DTP_Creator
  475.     - DTP_Check1
  476.     - DTP_Check2
  477.     - DTP_ExtLoad
  478.     - DTP_Config
  479.     - DTP_UserConfig
  480.  
  481.  
  482. 8. Checklist
  483.  
  484. This is a small list that you should match when you create your own player or
  485. custom module.
  486.  
  487.     [ ] checkroutine exact enough ?
  488.     [ ] audiochannel allocated/freed correctly ?
  489.     [ ] all allocated memory freed after playing?
  490.     [ ] all locks unlocked after playing ?
  491.     [ ] enforcer and mungwall proof ?
  492.     [ ] viable error handling path taken for ALL possible errors ?
  493.     [ ] player tested under 1.3 and 2.0 ?
  494.     [ ] does the player work correct in all videomodes ?
  495.  
  496.  
  497. 9. Other things
  498.  
  499. The player should not change the LED condition because DeliTracker will handle
  500. it.
  501.  
  502. Problems
  503.  
  504. Symptom        possible source                elimination
  505.  
  506. crash        a5 trashed, other registers
  507.         not saved, wrong stack usage
  508.         initialization wrong or too late 
  509.         module too new for the replayroutine    better check
  510.  
  511. module sounds    Audio data not in chipmem
  512. wrong        wrong initialization
  513.         module too new for the replayroutine
  514.         player needs some special values
  515.         in some registers            extra init code
  516.         wrong videomode
  517.  
  518. no sound    Audio-DMA off                :-)
  519.   >68000    player writes directly to processor    use OS routines to
  520.         intvectors and VBR is not 0.        set IntVectors
  521.  
  522. no free        wrong interrupt handling        VBlank-IRQ:
  523. CPU-time                        Z-Flag must be set
  524.                             at the end of the 
  525.                             interruptroutine. 
  526.  
  527. slow system    68000/020/030 toooo slow        buy a 68040 or
  528.                             CRAY ;-)
  529.  
  530.  
  531.  
  532.  
  533.  
  534.